"""
@author: badmonkey  # 作者名称
@software: PyCharm  # 使用的开发工具
@file: scanner.py   # 文件名
@time: 2021/4/7 上午9:50  # 文件创建时间
"""


# 定义一个状态类，用于表示词法分析过程中的各种状态
class State:
    START = "start"  # 开始状态
    ASSIGN = "assign"  # 赋值状态（未使用）
    COMMENT = "comment"  # 注释状态（未使用）
    NUM = "num"  # 数字状态
    ID = "id"  # 标识符状态
    CHAR = "char"  # 字符状态（未使用）
    RANGE = "range"  # 范围状态（未使用）
    DONE = "done"  # 完成状态（未使用）


# 从外部模块Lexer.token中导入必要的定义（如tokenType）
from Lexer.token import *

# 定义帮助信息，提示用户如何使用该词法分析器
HELP = '''
Usage: scanner filename output
Example: scanner demo-sort.txt result.txt
'''


# 定义词法分析主函数，参数scanner为输入的字符序列
def Scan(scanner):
    state = State.START  # 初始状态设置为START
    tokenList = list()  # 用于存储分析出的token列表
    line = 1  # 当前行号，初始为1
    nxt = 0  # 当前字符的索引位置
    length = len(scanner)  # 输入字符序列的总长度

    # 主循环，逐字符处理整个输入序列
    while nxt < length:
        # 如果当前状态是START（初始状态）
        if state == State.START:
            nxtChar = scanner[nxt]  # 获取当前字符
            # 跳过空白字符（空格、换行、回车、制表符）
            while nxt < length and (nxtChar == ' ' or nxtChar == '\n' or nxtChar == '\r' or nxtChar == '\t'):
                if nxtChar == '\n':  # 遇到换行符，行号加1
                    line += 1
                nxt += 1  # 移动到下一个字符
                if nxt == length:  # 如果到达末尾，退出循环
                    break
                nxtChar = scanner[nxt]  # 更新当前字符
            if nxt == length:  # 如果到达末尾，退出主循环
                break

            # 根据当前字符的类型切换状态
            if nxtChar.isalpha() or nxtChar == '_':  # 如果是字母或下划线，进入ID状态（标识符）
                state = State.ID
            elif nxtChar.isnumeric():  # 如果是数字，进入NUM状态
                state = State.NUM
            else:
                # 处理特殊符号（如范围符号".."或赋值符号":="）
                if nxt + 1 < length and nxtChar == '.' and scanner[nxt + 1] == '.':  # 检查是否为".."
                    nxt += 1  # 跳过第二个点
                    nxtChar = ".."  # 将符号设为".."
                elif nxt + 1 < length and nxtChar == ":" and scanner[nxt + 1] == '=':  # 检查是否为":="
                    nxt += 1  # 跳过等号
                    nxtChar = ":="  # 将符号设为":="
                elif nxtChar == "{":  # 处理注释，跳过{}之间的内容
                    while nxt < length and nxtChar != "}":  # 直到遇到结束符号"}"
                        nxt += 1
                        if nxt == length:  # 如果到达末尾，退出循环
                            break
                        nxtChar = scanner[nxt]  # 更新当前字符
                    if nxt < length:  # 如果未到末尾，继续移动
                        nxt += 1
                        if nxt < length:
                            nxtChar = scanner[nxt]
                    state = State.START  # 处理完注释后回到START状态
                    continue  # 继续下一次循环

                # 如果当前字符是已定义的token类型（如运算符、分隔符等）
                if nxtChar in tokenType.Types:
                    tokenList.append((nxtChar, nxtChar, line))  # 添加token到列表，格式为(类型, 值, 行号)
                    nxt += 1  # 移动到下一个字符
                    state = State.START  # 回到START状态
                else:
                    # 如果遇到无法识别的字符，打印错误信息并退出
                    print(nxt, nxtChar, state, "error", line, scanner[nxt:])
                    break

        # 如果当前状态是ID（标识符状态）
        elif state == State.ID:
            currentId = ""  # 用于存储当前标识符的字符串
            nxtChar = scanner[nxt]  # 获取当前字符
            # 持续读取字母、数字或下划线，直到遇到非标识符字符
            while nxt < length and (nxtChar.isalpha() or nxtChar.isnumeric() or nxtChar == '_'):
                currentId += nxtChar  # 将字符添加到标识符中
                nxt += 1  # 移动到下一个字符
                if nxt == length:  # 如果到达末尾，退出循环
                    break
                nxtChar = scanner[nxt]  # 更新当前字符
            # 检查是否为关键字
            if currentId.lower() in tokenType.KEYWORDS:  # 如果是关键字，转为大写并记录
                tokenList.append((currentId.upper(), currentId, line))
            else:  # 如果是普通标识符，记录为IDENTIFIERS类型
                tokenList.append((tokenType.IDENTIFIERS, currentId, line))
            state = State.START  # 处理完成后回到START状态

        # 如果当前状态是NUM（数字状态）
        elif state == State.NUM:
            currentNum = ""  # 用于存储当前数字的字符串
            nxtChar = scanner[nxt]  # 获取当前字符
            # 持续读取数字字符，直到遇到非数字字符
            while nxt < length and nxtChar.isnumeric():
                currentNum += nxtChar  # 将字符添加到数字中
                nxt += 1  # subscribe(nxt += 1)  # 移动到下一个字符
                if nxt == length:  # 如果到达末尾，退出循环
                    break
                nxtChar = scanner[nxt]  # 更新当前字符
            tokenList.append((tokenType.INTC, int(currentNum), line))  # 添加token到列表，格式为(类型, 值, 行号)
            state = State.START  # 处理完成后回到START状态

    return tokenList  # 返回分析得到的token列表


# 主程序入口
if __name__ == '__main__':
    # 读取输入文件bubble.txt的内容并转为字符列表
    scanner = list(open("../SNL_code_TEST/bubble.txt", "r").read())
    tokens = Scan(scanner)  # 调用Scan函数进行词法分析
    out = open("bubble-Lexer.txt", "w")  # 打开输出文件bubble-Lexer.txt
    print(1)  # 调试用，打印1表示程序运行到此处
    # 将分析结果逐行写入输出文件
    for i in tokens:
        out.write(str(i) + "\n")
    out.close()  # 关闭输出文件